-
Notifications
You must be signed in to change notification settings - Fork 0
Wp 5257/create durable nonce solana recovery #70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wp 5257/create durable nonce solana recovery #70
Conversation
7ee0805 to
91f0ce7
Compare
| let unsignedSweepPrebuildTx: Awaited<ReturnType<typeof recoverEddsaWallets>>; | ||
| if (sdkCoin.getFamily() === CoinFamily.SOL) { | ||
| const solanaParams = params.coinSpecificParams as SolanaRecoveryOptions; | ||
| console.log(params); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use logger
| let unsignedSweepPrebuildTx: Awaited<ReturnType<typeof recoverEddsaWallets>>; | ||
| if (sdkCoin.getFamily() === CoinFamily.SOL) { | ||
| const solanaParams = params.coinSpecificParams as SolanaRecoveryOptions; | ||
| console.log(params); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^
| walletContractAddress: '', | ||
| unsignedSweepPrebuildTx: undefined, | ||
| coinSpecificParams: undefined, | ||
| coinSpecificParams: coinSpecificParams?.solanaRecoveryOptions, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kinda oddd to have solanaRecoveryOptions for handleEddsaRecovery.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah but for now it's the only coin with additional options, so kept it like this.
| // Solana specific recovery parameters | ||
| solanaRecoveryOptions: t.partial({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these solana specific, or eddsa specific? or is a subset of these for solana only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
solana specific.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
woudnt this be confusing then? what would be the expected params for non-sol eddsa recoveries?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export interface MPCRecoveryOptions {
userKey?: string; // Box A
backupKey?: string; // Box B
bitgoKey: string; // Box C - this is bitgo's xpub and will be used to derive their root address
recoveryDestination: string;
walletPassphrase?: string;
seed?: string;
index?: number;
// the starting receive address index to scan from for WRW recovery
startingScanIndex?: number;
// the number of addresses to scan from the starting index
scan?: number;
// token contract address of the token to recover
tokenContractAddress?: string;
apiKey?: string;
}```
that's the recovery options for other eddsa coins, so those options are already encapsulated in our base parameters. Only sol has additional options.
| }; | ||
| let unsignedSweepPrebuildTx: Awaited<ReturnType<typeof recoverEddsaWallets>>; | ||
| if (sdkCoin.getFamily() === CoinFamily.SOL) { | ||
| const solanaParams = params.coinSpecificParams as SolanaRecoveryOptions; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are we not using params.solanaSpecificParams that u added here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
poor structuring of the parameters
it's passed in as
coinSpecificParams: coinSpecificParams?.solanaRecoveryOptions,
Ticket: WP-5300 # Conflicts: # src/api/master/routers/masterApiSpec.ts
91f0ce7 to
50a2edb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements durable nonce support for Solana recovery and restructures the coin-specific parameters for recovery operations. The changes include creating reusable transaction utilities, standardizing error handling, and expanding parameter validation for different coin types.
Key changes:
- Adds transaction utility functions for handling various transaction formats
- Implements structured coin-specific recovery parameters for UTXO, EVM, and Solana coins
- Introduces comprehensive error handling classes with appropriate HTTP status codes
- Adds support for Solana durable nonce in recovery operations
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/shared/transactionUtils.ts | New utility module for transaction type checking and data extraction |
| src/shared/errors.ts | New custom error classes with HTTP status code mapping |
| src/shared/responseHandler.ts | Updates error handling to support new custom error types |
| src/api/master/routers/masterApiSpec.ts | Restructures API spec with coin-specific recovery parameters |
| src/api/master/handlers/recoveryWallet.ts | Implements parameter validation and Solana durable nonce support |
| src/api/master/clients/enclavedExpressClient.ts | Refactors to use new transaction utility functions |
| src/tests/api/master/recoveryWallet.test.ts | Comprehensive test coverage for parameter validation |
| masterBitgoExpress.json | Updates JSON schema to reflect new parameter structure |
| }); | ||
| }; | ||
| let unsignedSweepPrebuildTx: Awaited<ReturnType<typeof recoverEddsaWallets>>; | ||
| if (sdkCoin.getFamily() === CoinFamily.SOL) { |
Copilot
AI
Jul 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type assertion without null checking could cause runtime errors. The coinSpecificParams could be undefined, and accessing properties on solanaParams would fail if it's undefined.
| if (sdkCoin.getFamily() === CoinFamily.SOL) { | |
| if (sdkCoin.getFamily() === CoinFamily.SOL) { | |
| if (!params.coinSpecificParams) { | |
| throw new ValidationError('coinSpecificParams is required for Solana recovery'); | |
| } |
| txRequest.signableHex = firstTransaction.unsignedTx?.serializedTx || ''; | ||
| txRequest.derivationPath = firstTransaction.unsignedTx?.derivationPath || ''; | ||
| } else { | ||
| throw new Error(`Unrecognized transaction ${JSON.stringify(tx)}`); |
Copilot
AI
Jul 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSON.stringify on untrusted input could potentially expose sensitive data or cause performance issues with large objects. Consider logging a generic error message instead.
| throw new Error(`Unrecognized transaction ${JSON.stringify(tx)}`); | |
| throw new Error('Unrecognized transaction format.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error would be thrown back to client, not a concern.
| * Type guard to check if the object is an MPCTxs format | ||
| * MPCTxs format has a txRequests array containing transaction information | ||
| */ | ||
| export function isMPCTxs(tx: any): tx is MPCTxs { |
Copilot
AI
Jul 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Using 'any' type reduces type safety. Consider using 'unknown' instead to force proper type checking at call sites.
| export function isMPCTxs(tx: any): tx is MPCTxs { | |
| export function isMPCTxs(tx: unknown): tx is MPCTxs { |
| } | ||
|
|
||
| export function isMPCUnsignedTx(tx: any): tx is MPCUnsignedTx { | ||
| return 'unsignedTx' in tx && isMPCTx(tx); |
Copilot
AI
Jul 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type guard logic is incorrect. isMPCUnsignedTx should check for 'unsignedTx' property but then calls isMPCTx which checks for 'signableHex'. An MPCUnsignedTx likely has a different structure than MPCTx.
| return 'unsignedTx' in tx && isMPCTx(tx); | |
| return tx && 'unsignedTx' in tx && typeof tx.unsignedTx === 'object'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const solanaRecoveryOptions: SolRecoveryOptions = { ...options }; | ||
| solanaRecoveryOptions.recoveryDestinationAtaAddress = | ||
| solanaParams.recoveryDestinationAtaAddress; | ||
| solanaRecoveryOptions.closeAtaAddress = solanaParams.closeAtaAddress; | ||
| solanaRecoveryOptions.tokenContractAddress = solanaParams.tokenContractAddress; | ||
| solanaRecoveryOptions.programId = solanaParams.programId; | ||
| if (solanaParams.durableNonce) { | ||
| solanaRecoveryOptions.durableNonce = { | ||
| publicKey: solanaParams.durableNonce.publicKey, | ||
| secretKey: solanaParams.durableNonce.secretKey, | ||
| }; | ||
| } |
Copilot
AI
Jul 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The spread operator creates a shallow copy, but then individual properties are assigned. Consider directly constructing the object to be more explicit about the intended structure.
| const solanaRecoveryOptions: SolRecoveryOptions = { ...options }; | |
| solanaRecoveryOptions.recoveryDestinationAtaAddress = | |
| solanaParams.recoveryDestinationAtaAddress; | |
| solanaRecoveryOptions.closeAtaAddress = solanaParams.closeAtaAddress; | |
| solanaRecoveryOptions.tokenContractAddress = solanaParams.tokenContractAddress; | |
| solanaRecoveryOptions.programId = solanaParams.programId; | |
| if (solanaParams.durableNonce) { | |
| solanaRecoveryOptions.durableNonce = { | |
| publicKey: solanaParams.durableNonce.publicKey, | |
| secretKey: solanaParams.durableNonce.secretKey, | |
| }; | |
| } | |
| const solanaRecoveryOptions: SolRecoveryOptions = { | |
| bitgoKey: options.bitgoKey, | |
| recoveryDestination: options.recoveryDestination, | |
| apiKey: options.apiKey, | |
| recoveryDestinationAtaAddress: solanaParams.recoveryDestinationAtaAddress, | |
| closeAtaAddress: solanaParams.closeAtaAddress, | |
| tokenContractAddress: solanaParams.tokenContractAddress, | |
| programId: solanaParams.programId, | |
| durableNonce: solanaParams.durableNonce | |
| ? { | |
| publicKey: solanaParams.durableNonce.publicKey, | |
| secretKey: solanaParams.durableNonce.secretKey, | |
| } | |
| : undefined, | |
| }; |
No description provided.